package gameManager;

import java.util.Collections;
import java.util.LinkedList;
import java.util.Random;
import common.Move;
import common.Piece;
import common.Side;
import agent.Agent;
import common.DominoState;

public class GameManager {

    public static final int RANDOM_ALGORITHM = 1;
    public static final int ALPHA_BETA = 2;
    private GameState currentState;
    private Agent upperPlayer;
    private Agent downPlayer;
    private LinkedList<Piece> pieces;
    private Random randomDealer;
    private LinkedList<Piece> upperPlayerPieces;
    private LinkedList<Piece> downPlayerPieces;
    private Player player;

    public GameManager() {
        currentState = new GameState();
    }

    public void createUpperPlayer(int depthLimit, int handsLimit, int handsSeed, int algorithm) {
        upperPlayer = new Agent(handsSeed);
        configureAgent(upperPlayer, depthLimit, handsLimit, algorithm);
    }

    public void createDownPlayer(int depthLimit, int handsLimit, int handsSeed, int algorithm) {
        downPlayer = new Agent(handsSeed);
        configureAgent(downPlayer, depthLimit, handsLimit, algorithm);
    }

    private void configureAgent(Agent agent, int depthLimit, int handsLimit, int algorithm) {
        if (algorithm == RANDOM_ALGORITHM) {
            agent.useRandomAlgorithm();
        } else {
            agent.useAlfabeta();
            agent.setHandsLimit(handsLimit);
            agent.setSearchDepth(depthLimit);
        }
    }

    public GameOutcome playGame(int dealerSeed) {
        restart(dealerSeed);
        shufflePieces();
        currentState.restart(upperPlayerPieces, downPlayerPieces);

        playerWithHigherDoublePieceStarts();

        while (!currentState.isEndOfGameState()) {

            if (player == Player.UPPER) {
                if (currentState.upperPlayerCanPlay()) {
                    Move move = upperPlayer.play();
                    if (currentState.placePiece(move.getSide(), move.getPiece())) {
                        upperPlayer.notifyAgentMove(move);
                        downPlayer.notifyOpponentMove(move);
                    }
                }
                player = Player.DOWN;
            } else if (player == Player.DOWN) {
                if (currentState.downPlayerCanPlay()) {
                    Move move = downPlayer.play();
                    if (currentState.placePiece(move.getSide(), move.getPiece())) {
                        downPlayer.notifyAgentMove(move);
                        upperPlayer.notifyOpponentMove(move);
                    }
                }
                player = Player.UPPER;
            }
        }

        return currentState.getWinner();
    }

    private void restart(int dealerSeed) {
        randomDealer = new Random(dealerSeed);
        upperPlayerPieces = new LinkedList<>();
        downPlayerPieces = new LinkedList<>();
    }

    private void shufflePieces() {
        pieces = DominoState.getAllPiecesList();
        Collections.shuffle(pieces, randomDealer);

        for (int i = 0; i < DominoState.PIECES_PER_PLAYER; i++) {
            Piece piece = pieces.removeFirst();
            upperPlayerPieces.add(piece);
            piece = pieces.removeFirst();
            downPlayerPieces.add(piece);
        }

        upperPlayer.setInitialPiecesSet(upperPlayerPieces);
        downPlayer.setInitialPiecesSet(downPlayerPieces);
    }

    private void playerWithHigherDoublePieceStarts() {
        byte startPiece = DominoState.DOMINO_ORDER;
        while (true) {
            Piece doublePiece = new Piece(startPiece, startPiece);
            if (upperPlayerPieces.contains(doublePiece)) {
                Move move = new Move(Side.LEFT, doublePiece);
                currentState.placePiece(Side.LEFT, doublePiece);
                upperPlayer.notifyAgentMove(move);
                downPlayer.notifyOpponentMove(move);
                player = Player.DOWN;
                break;
            }
            if (downPlayerPieces.contains(new Piece(startPiece, startPiece))) {
                Move move = new Move(Side.LEFT, doublePiece);
                currentState.placePiece(Side.LEFT, doublePiece);
                downPlayer.notifyAgentMove(move);
                upperPlayer.notifyOpponentMove(move);
                player = Player.UPPER;
                break;
            }
            startPiece--;
        }

    }
}
